local specification = require('specification')
local struct = require('struct')
local myUtils = require('myutils')

local _M = {
  PROTOCOL_VERSION = 0,
}

_M.OP_CODES = {
  NOTIFICATION = 0,
  CREATE = 1,
  DELETE = 2,
  EXISTS = 3,
  GET_DATA = 4,
  SET_DATA = 5,
  GET_ACL = 6,
  SET_ACL = 7,
  GET_CHILDREN = 8,
  SYNC = 9,
  PING = 11,
  GET_CHILDREN2 = 12,
  CHECK = 13,
  MULTI = 14,
  AUTH = 100,
  SET_WATCHES = 101,
  SASL = 102,
  CREATE_SESSION = -10,
  CLOSE_SESSION = -11,
  ERROR = -1
}

local mapperMeta = {
  ending ='>' ,
  int = "i",
  long = "l",
  buffer = "S",
  boolean = "B",
  ustring = "S"
}

-- how to parse
-- vector<ustring>
-- data.Stat


function _M.makeBuffer(length, byte)
  local str = string.char(byte or 0x00)
  local tbl = {}
  for i = 1,length do
    table.insert(tbl, str)
  end
  local format = table.concat(tbl)
  return format
end


-- load all protocol mapper
local mapper = {}
for protocolName, descTbl in pairs(specification.protocol) do
  local mapStr = mapperMeta.ending
  for _, keyDesc in pairs(descTbl) do
    if mapperMeta[keyDesc.type] == nil then
      print("no such mapper keyDesc.type "..keyDesc.type)
    else
      mapStr = mapStr .. mapperMeta[keyDesc.type]
    end
  end
  -- print(protocolName..'='..mapStr)
  mapper[protocolName] = mapStr
end

-- description
function _M.pack(protocolType, ...)
  -- print("now pack"..protocolType)
  -- print(select('#',...), ...)

  local mapStr = mapper[protocolType]
  print('pack, protocol=' .. protocolType .. ', mapStr=' .. mapStr)
  local packed = struct.pack(mapStr, ...);
  -- print(type(packed))

  local len = #packed -- string.len(packed)
  local byte4 = packInt(len)
  local tbl = {byte4, packed}
  return table.concat(tbl)

    -- return packed
end

function _M.packWithHeader(protocolType, header, ...)
  local mapStr = mapper[protocolType]
  print('packWithHeader, protocol=' .. protocolType .. ', mapStr=' .. mapStr)
  local packed = struct.pack(mapStr, ...);
  local len = #packed + #header
  print("len="..len)
  local byte4 = packInt(len)
  local tbl = {byte4, header, packed}
  return table.concat(tbl)
end

-- description
function _M.unpack(protocolType, ...)
  print("now unpack"..protocolType)
  -- print(select('#',...), ...)

  local mapStr = mapper[protocolType]
  local unpacked = struct.unpack(mapStr, ...)
  -- for k,v in pairs(unpacked) do
  --   print(k,v)
  -- end
  -- return unpacked
  local retTbl = {}
  local theProtocol = specification.protocol[protocolType]

  for i, v in pairs(theProtocol) do
    local name = v.name
    local value = unpacked[i]
    retTbl[name] = value
  end
  return retTbl
end

-- 4 byte -> int valuve
function  unpackInt(byte4)
  local obj = struct.unpack('>i',byte4)
  print(type(obj))
  print(myUtils.printObj(obj))
  return obj[1]
    -- return obj
end

-- int value -> 4 bytes
function packInt(intValue)
  local obj = struct.pack('>i', intValue)
  print(myUtils.printObj(obj))
  return obj
end

_M.packInt = packInt
_M.unpackInt = unpackInt


return _M









































